package cn.xinfei.xdecision.engine.runner.executor.handler;

import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.api.AbstractDecision;
import cn.xinfei.xdecision.engine.runner.context.BranchTypeEnum;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.PipelineMetaInfoContext;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.DecisionFlowPipeline;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.XRunner;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.metadata.MetadataProvider;
import cn.xinfei.xdecision.model.DecisionApiResponse;
import com.dianping.cat.Cat;
import io.micrometer.core.instrument.Metrics;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ExecutorService;

/**
 * 冠军挑战节点
 */
@XRunner
@Service
@Slf4j
public class ChampionChallengeHandler extends AbstractDecision<NodeHandler, DecisionApiResponse> {

    @Resource(name = "decisionChallengeThreadPool")
    private ExecutorService decisionChallengeThreadPool;


    @Autowired
    protected MetadataProvider metadataProvider;


    @Override
    public DecisionApiResponse run(NodeHandler challengeNode) {
        DecisionApiResponse engineApiResponse = new DecisionApiResponse();
        String businessId = PipelineContextHolder.getRequestId();
        String decisionId = PipelineContextHolder.getDecisionId();
        engineApiResponse.setEngineResult(EngineResultEnum.SUCCESS_END);
        try {
            StateTransmitModel stateTransmitModel = DecisionFlowPipeline.shoot(challengeNode);
            EngineResultEnum engineResultEnum = stateTransmitModel.getEngineResultEnum();
            String result = PipelineContextHolder.getResult(engineResultEnum);
            engineApiResponse.setEngineResult(engineResultEnum);
            engineApiResponse.setResult(result);
            PipelineContextHolder.setEngineResult(engineResultEnum);
        } catch (Exception e) {
            log.error("挑战者分支执行节点流异常，node={}，error={}", challengeNode.getEngineNode().getNodeCode(), e.getMessage(), e);
            engineApiResponse.setEngineResult(EngineResultEnum.EXCEPTION_END);
        }

        engineApiResponse.setDecisionId(decisionId);
        engineApiResponse.setRequestId(businessId);
        return engineApiResponse;
    }

    /**
     * DecisionApiResponse response = engineRunApi.execute(engineApiRequest);
     *
     * @param nextNode
     */
    public void asyncHandler(String championNodeCode, String nextNode,String nodeIndex, int challengeIndex) {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();

        String mainDecisionId = PipelineContextHolder.getMainDecisionId();
        String championDecisionId = PipelineContextHolder.getDecisionId();
        XDecisionContext newXDecisionContext = xDecisionContext.clone();
        decisionChallengeThreadPool.execute(() -> {
            try {
                //将当前子线程的上线文设置为父线程的上下文的深拷贝
                //XDecisionContext.destroy();
                XDecisionContext newContext = cloneContext4Challenge(newXDecisionContext, nodeIndex,challengeIndex);
                PipelineContextHolder.setBranch(BranchTypeEnum.CHALLENGE.name());
                PipelineContextHolder.setChampionDecisionId(championDecisionId);
                PipelineContextHolder.setMainDecisionId(mainDecisionId);
                log.info("异步进入挑战者分支,nodeCode={}", nextNode);
                PipelineMetaInfoContext pipelineMetaInfoContext = newContext.getPipelineMetaInfoContext();
                NodeHandler challengeNode = pipelineMetaInfoContext.get(nextNode);
                this.execute(challengeNode);
                log.info("挑战者分支执行结果,EngineResult={},pop championNodeCode={}", PipelineContextHolder.getEngineResult(), championNodeCode);
                PipelineContextHolder.popNodeContextModel(championNodeCode);
            } catch (Exception e) {
                log.error("挑战者分支执行节点流异常 fail.error={},", e.getMessage(), e);
                Cat.logError(e);
                Metrics.counter("xdecision_node_challenge_error_total").increment();
            } finally {
                MDC.clear();
            }

        });
    }

    public XDecisionContext cloneContext4Challenge(XDecisionContext clone,String nodeIndex, int challengeIndex) {
        XDecisionContext.setContext(clone);
        XDecisionContext newContext = XDecisionContext.getContext();
        String engineCode = PipelineContextHolder.getEngineCode();

        try {
            Map<String, NodeHandler> engineNodeMap = metadataProvider.getEngineNodeList(engineCode);
            newContext.getPipelineMetaInfoContext().putAll(engineNodeMap);

            String decisionId = PipelineContextHolder.getDecisionId();
            String newDecisionId = decisionId + "_X"+nodeIndex+"_" + challengeIndex;
            //更新decisionId
            log.info("产生新的挑战分组newDecisionId={}", newDecisionId);
            PipelineContextHolder.setDecisionId(newDecisionId);
        } catch (Exception e) {
            //此异常严重，需要立即处理
            log.error("上下文深拷贝异常，context={},msg={}", PipelineContextHolder.toJson(), e.getMessage(), e);
        }

        return newContext;
    }

}
